home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / v7n22.arc / ENVELOPE.ASM < prev    next >
Assembly Source File  |  1988-12-07  |  49KB  |  1,193 lines

  1. ;======================================================================
  2. ;  ENVELOPE: Print envelopes on LaserJet Printers * PC Magazine
  3. ;-----------------------------------------------------------------------
  4. ;       EQUATES
  5. ;-----------------------------------------------------------------------
  6. LF        EQU    0Ah        ; Line feed
  7. CR        EQU    0Dh        ; Carriage return
  8. ESCAPE          EQU    1Bh        ; Escape
  9. SCAN_CODE       EQU    18        ; scan code for E
  10. SHIFT_MASK      EQU    8        ; shift status for Alt
  11. LJ_MODEL        EQU           1B    ; Printer Flag Bit in status
  12. PR_RET_ADD      EQU          10B    ; Print Return Address Flag
  13. ENV_SIZE_BIT    EQU         100B    ; Envelope Size (Large if set)
  14. EGA             EQU     1000000B    ; EGA Flag
  15. INSTALLED       EQU    10000000B    ; Installed Flag
  16. ;-----------------------------------------------------------------------
  17. ;       EQUATES  for Envelope Margins - Note Bytes reversed
  18. ;-----------------------------------------------------------------------
  19. LMARG_ADD_S     EQU     "06"            ; Left Address Margin - Small
  20. LMARG_RET_S     EQU     "54"            ; Left Return Margin - Small
  21. LMARG_ADD_L     EQU     "05"            ; Left Address Margin - Large
  22. LMARG_RET_L     EQU     "71"            ; Left Return Margin - Large
  23. TMARG_RET_S     EQU     "03"            ; Top Return Margin - Small
  24. TMARG_RET_L     EQU     "92"            ; Top Return Margin - Large
  25. TMARG_RET_2     EQU     "61"            ; Top Return Margin - Series 2
  26. ;----------------------------------------------------------------------
  27. CSEG            SEGMENT PUBLIC  'CODE'
  28.         ASSUME  CS:CSEG,DS:CSEG,ES:CSEG,SS:CSEG
  29.  
  30.         ORG     100H
  31. START:          JMP     INSTALL         ; install TSR program
  32.  
  33. COPYRIGHT$  DB  "ENVELOPE 1.0 Copyright (c) 1988 Ziff Communications Co."
  34.         DB  CR,LF,"PC Magazine ",254," R. M. Saidikowski",CR,LF,"$",26
  35. ;-----------------------------------------------------------------------
  36. ;  Program Data Area -- Static text first for Residency Check
  37. ;-----------------------------------------------------------------------
  38. TEXT_UPPER      DB      "ark Upp",0,"Left ",0
  39. TEXT_LOWER      DB      "ove Low",0,"Right",0
  40.  
  41. OLD09H          DD      0               ; Holds old Interrupt 09H vector
  42. BUSY            DB      0               ; busy flag for ENVELOPE
  43. ; status byte for ENVELOPE       ;  bit 0 = LJ Series 2  if set
  44. ;  bit 1 = Print return address  ;  bit 2 = Large Envelope
  45. ;  bit 6 = EGA video adapter     ;  bit 7 = ENVELOPE installed
  46. STATUS          DB      00000101B
  47. CURLOC          DW      0               ; save cursor location
  48. VID_PAGE        DB      0               ; current video page
  49. NUM_COLS        DB      80              ; number columns in display
  50. LAST_COL        DB      79              ; last column number
  51. LAST_LINE       DB      24              ; last line number
  52. ADDR_COLS       DB      0               ; columns in address
  53. START_COL       DB      0               ; starting column for swap
  54. UPLEFT          DW      0               ; upper left position of box
  55. BOTRIGHT        DW      0               ; bottom right position of box
  56. HILITE_LOC      DW      0               ; highlight location of Small
  57. PRINT_PORT      DW      0               ; 0-2=LPT1-LPT3, 3-6=COM1-COM4
  58.  
  59. MENU_BLOCK      DB      0DAH,7,10 DUP(0C4H,7),0BFH,7,0B3H,7,"M",7,"a",7
  60.         DB      "r",7,"k",7," ",7,"U",7,"p",7,"p",7,"e",7,"r",7
  61.         DB      2 DUP(0B3H,7),"L",7,"e",7,"f",7,"t",7," ",7
  62.         DB      " ",7,"&",7,17,7,0C4H,7,0D9H,7,0B3H,7,0C0H,7
  63.         DB      0C4H,7,"E",7,"s",7,"c",7,"=",7,"E",7,"x",7
  64.         DB      "i",7,"t",7,0C4H,7,0D9H,7
  65.  
  66. MENU_PRINT      DB      0C9H,7,8 DUP(0CDH,7),0BBH,7,0BAH,7,"F",7,"1",7
  67.         DB      "-",7,"S",7,"m",7,"a",7,"l",7,"l",7,0BAH,7
  68.         DB      0BAH,7,"F",7,"2",7,"-",7,"L",7,"a",7,"r",7,"g",7
  69.         DB      "e",7,2 DUP(0BAH,7),"F",7,"3",7,"-",7,"R",7
  70.         DB      "t",7,"A",7,"d",7,"d",7,0BAH,7,0C7H,7
  71.         DB      8 DUP(0C4H,7),0B6H,7,0BAH,7,"L",7,"P",7,"T",7
  72.         DB      "1",7," ",7,"L",7,"J",7,"2",7,2 DUP(0BAH,7)
  73.         DB      17,7,0C4H,7,0D9H,7,"P",7,"r",7,"i",7,"n",7,"t",7
  74.         DB      0BAH,7,0C8H,7,"E",7,"s",7,"c",7,"=",7,"E",7
  75.         DB      "x",7,"i",7,"t",7,0BCH,7
  76.  
  77. LINE_SIZE    EQU    40
  78. RET_ADD        DB    LINE_SIZE DUP(32),CR,LF
  79.         DB    LINE_SIZE DUP(32),CR,LF
  80.         DB    LINE_SIZE DUP(32)
  81. SKIP_LINE       DB      CR,LF,0,"$"
  82. LENGTH_RET    =    (LINE_SIZE + 2) * 3
  83. ;-----------------------------------------------------------------------
  84. ; Laser Jet Command Sequences
  85. ;-----------------------------------------------------------------------
  86. RESET_LJ        DB      ESCAPE,"E",0    ; reset printer
  87. FONT            DB      ESCAPE,"&l1O"   ; landscape
  88.         DB      ESCAPE,"(8U"    ; Roman-8 symbol set
  89.         DB      ESCAPE,"(sp10h12vsb3T"  ; 10-pitch  12-point
  90.                                 ; upright  med-weight  Courier
  91.         DB      ESCAPE,"&l2H",0 ; manual feed
  92. TOP_MARGIN      DB      ESCAPE,"&l"     ; skip lines
  93. MODELX          DB      "16E",0         ; 16 for LJII  30 for LJ and LJ+
  94. LEFT_MARGIN     DB      ESCAPE,"&a"     ; left margin
  95. ENV_SIZE        DB      "50L",0         ; 50 spaces - default Large
  96. ;-----------------------------------------------------------------------
  97. ; Arrow Key Jump Offsets
  98. ;-----------------------------------------------------------------------
  99. KEYTAB          DB      72, 75 , 77  , 80    ; Up Left Right Down
  100. JMPTAB_TOP      DW      OFFSET TOP_UP,OFFSET TOP_LEFT
  101.         DW      OFFSET TOP_RIGHT,OFFSET TOP_DOWN
  102. JMPTAB_BOT      DW      OFFSET BOT_UP,OFFSET BOT_LEFT
  103.         DW      OFFSET BOT_RIGHT,OFFSET BOT_DOWN
  104. ;======================================================================
  105. ;  Intercept Keyboard Interrupt
  106. ;-----------------------------------------------------------------------
  107. INT09H          PROC    FAR
  108.     ASSUME  CS:CSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING
  109.  
  110.         STI                     ; Turn interrupts back on
  111.         PUSH    AX
  112.         IN      AL,60H          ; get scan code
  113.         CMP     AL,SCAN_CODE    ; compare scan code
  114.         JNE     INT9_2          ; if not, exit to old INT09H
  115.         MOV     AH,2            ; shift key status
  116.         INT     16H             ; BIOS
  117.         AND    AL,0FH
  118.         CMP     AL,SHIFT_MASK   ; compare shift status
  119.         JE      INT9_3          ; if yes, check if routine busy
  120. INT9_2:         POP     AX
  121.         CLI                     ; flags already pushed
  122.         JMP     DWORD PTR CS:[OLD09H]   ; look like an interrupt
  123. ;-----------------------------------------------------------------------
  124. ; More ckecks before calling main ENVELOPE routine
  125. ;-----------------------------------------------------------------------
  126. INT9_3:         CMP     CS:[BUSY],0     ; ENVR already active?
  127.         JNE     INT9_2          ; normal exit
  128.         IN      AL,61H          ; reset keyboard
  129.         MOV     AH,AL
  130.         OR      AL,80H          ; set bit 7
  131.         OUT     6AH,AL          ; send to control port
  132.         MOV     AH,AL           ; recover old value
  133.         JMP     SHORT  $+2
  134.         OUT     6AH,AL          ; send to control port
  135.         CLI
  136.         MOV     AL,20H          ; reset the
  137.         OUT     20H,AL          ; interrupt controller
  138.         STI
  139.         PUSH    BX              ; AX already pushed
  140.         PUSH    CX
  141.         PUSH    DX
  142.         PUSH    SI              ; Save all registers
  143.         PUSH    DI
  144.         PUSH    DS
  145.         PUSH    ES
  146.         PUSH    BP
  147.  
  148.         PUSH    CS              ; establish addressing
  149.         POP     DS
  150.     ASSUME  DS:CSEG
  151.         INC     [BUSY]          ; set busy flag
  152. ;-----------------------------------------------------------------------
  153. ; Get screen parameters  --  part of test if interrupt OK
  154. ;-----------------------------------------------------------------------
  155.         MOV     AH,0FH          ; get video mode
  156.         INT     10H             ; BIOS video
  157.         CMP     AL,7            ; MONO
  158.         JE      MODEOK
  159.         CMP     AL,3            ; regular 40 and 80 column modes
  160.         JA      INT09_X         ; graphics mode - exit
  161. MODEOK:         MOV     [NUM_COLS],AH   ; number of columns
  162.         DEC     AH
  163.         MOV     [LAST_COL],AH   ; last column number
  164.         MOV     [VID_PAGE],BH   ; video page
  165.         TEST    [STATUS],EGA    ; check if EGA (or VGA)
  166.         JZ      SET_LINES       ; not EGA
  167.         XOR    AX,AX
  168.         MOV    ES,AX
  169.         MOV    AL,BYTE PTR ES:[484H]
  170.         MOV    [LAST_LINE],AL
  171. SET_LINES:      PUSH    CS              ; set segment
  172.         POP     ES              ; for ES
  173.     ASSUME    ES:CSEG
  174.         CALL    GET_CURSOR      ; get current cursor attributes
  175.         MOV     [CURLOC],DX     ; save cursor position
  176.         CALL    ENVL_MAIN       ; call main envelope routine
  177.         MOV     DX,[CURLOC]     ; saved cursor location
  178.         CALL    SET_CURSOR      ; restore cursor
  179. INT09_X:    DEC     [BUSY]          ; Envelope finished
  180.     ASSUME  DS:NOTHING, ES:NOTHING
  181.         POP     BP
  182.         POP     ES
  183.         POP     DS
  184.         POP     DI              ; restore all registers
  185.         POP     SI
  186.         POP     DX
  187.         POP     CX
  188.         POP     BX
  189.         POP     AX
  190.         IRET                    ; return to Interrupted Routine
  191.  
  192. INT09H          ENDP
  193. ;======================================================================
  194. ; Main ENVELOPE Routine
  195. ;-----------------------------------------------------------------------
  196. ENVL_MAIN       PROC    NEAR
  197.         ASSUME  CS:CSEG,DS:CSEG,ES:CSEG,SS:NOTHING
  198. ;-----------------------------------------------------------------------
  199. ; Define address on screen
  200. ; Display upper left message and cursor in upper left
  201. ;-----------------------------------------------------------------------
  202.         MOV     UPLEFT,0        ; initialize
  203.         CALL    BLOCK_WINDOW    ; place window on screen
  204.         XOR     DX,DX           ; upper left location
  205.         CALL    SET_CURSOR
  206.         CALL    GET_CHAR        ; get character
  207.         PUSH    AX              ; save character
  208.         CALL    BLOCK_WINDOW    ; remove window from screen
  209. ;-----------------------------------------------------------------------
  210. ; set text in window for lower right corner message
  211. ;-----------------------------------------------------------------------
  212.         MOV     SI,OFFSET TEXT_LOWER     ; text for lower message
  213.         MOV     DI,OFFSET MENU_BLOCK+28  ; window location
  214.         CALL    MOV_TEXT
  215.         MOV     DI,OFFSET MENU_BLOCK+50  ; window location
  216.         CALL    MOV_TEXT        ; move 'right' message
  217.         XOR     DX,DX           ; cursor location
  218.         CALL    SET_CURSOR
  219.         POP     AX              ; recover character
  220.         JMP     SHORT  TOP_WIN_GONE
  221. TOP_BADKE:      CALL    BEEP            ; illegal key
  222. TOP_NEXT:       CALL    SET_CURSOR      ; set cursor
  223. TOP_NEXT_KE:    CALL    GET_CHAR        ; get character
  224. TOP_WIN_GONE:   MOV     UPLEFT,DX       ; save cursor location
  225.         CMP     AL,CR           ; carriage return
  226.         JE      MOV_BOT_RT      ; finished with top-left moves
  227.         CMP     AL,ESCAPE       ; Quit
  228.         JNE     TOP_NOT_ESC
  229.         JMP     ENV_EXIT        ; exit ENVELOPE
  230. TOP_NOT_ESC:    OR      AL,AL           ; extended key code
  231.         JNZ     TOP_NEXT_KE
  232.         MOV     BX,OFFSET JMPTAB_TOP+6  ; last entry in table
  233.         CALL    GET_JMP_OFF     ; get jump offset
  234.         JC      TOP_BADKE       ; no match
  235.         JMP     [DI]            ; offset returned by Call
  236. TOP_UP:         OR      DH,DH           ; row number in DH
  237.         JE      TOP_BADKE       ; can't move higher
  238.         DEC     DH
  239.         JMP     TOP_NEXT        ; get next cursor movement
  240. TOP_LEFT:       OR      DL,DL           ; column number in DL
  241.         JE      TOP_BADKE       ; can't move to left
  242.         DEC     DL
  243.         JMP     TOP_NEXT        ; get next cursor movement
  244. TOP_RIGHT:      CMP     DL,LAST_COL     ; column number in DL
  245.         JE      TOP_BADKE       ; can't move to right
  246.         INC     DL
  247.         JMP     TOP_NEXT        ; get next cursor movement
  248. TOP_DOWN:       CMP     DH,LAST_LINE    ; row number in DH
  249.         JE      TOP_BADKE       ; can't move lower
  250.         INC     DH
  251.         JMP     TOP_NEXT        ; get next cursor movement
  252. ;-----------------------------------------------------------------------
  253. ; now move to bottom right corner to define address
  254. ; first  --  display window and reverse video upper-left
  255. ;-----------------------------------------------------------------------
  256. MOV_BOT_RT:     CALL    BLOCK_WINDOW    ; move window on screen
  257.         MOV     DX,UPLEFT       ; current location
  258.         CALL    SET_CURSOR
  259.         PUSH    DX              ; save cursor loc
  260.         CALL    REVERSE         ; reverse video
  261.         CALL    BURY_CURSOR
  262.         CALL    GET_CHAR
  263.         PUSH    AX              ; save character
  264.         CALL    BLOCK_WINDOW    ; remove window
  265.         POP     AX              ; recover character
  266.         POP     DX              ; recover cursor location
  267.         JMP     SHORT  BOT_WIN_GONE
  268. BOT_BADKE:      CALL    BEEP            ; illegal key
  269. BOT_NEXTKE:     CALL    GET_CHAR        ; get character
  270. BOT_WIN_GONE:   MOV     BOTRIGHT,DX     ; save cursor location
  271.         CMP     AL,CR           ; carriage return
  272.         JE      PRINT_MENU      ; display print window
  273.         CMP     AL,ESCAPE       ; Quit
  274.         JNE     BOT_NOT_ESC     ; not Escape
  275.         JMP     SCREEN_RST      ; restore screen
  276. BOT_NOT_ESC:    OR      AL,AL           ; extended key code
  277.         JNZ     BOT_NEXTKE
  278.         MOV     BX,OFFSET JMPTAB_BOT+6  ; last entry in table
  279.         CALL    GET_JMP_OFF     ; get jump offset
  280.         JC      BOT_BADKE       ; no match
  281.         MOV     BX,UPLEFT       ; upper left location
  282.         JMP     [DI]            ; offset returned by Call
  283. BOT_UP:         CMP     DH,BH           ; compare to top
  284.         JE      BOT_BADKE       ; can't move up
  285.         DEC     DH              ; new bottom right location
  286.         PUSH    DX              ; save
  287.         INC     DH              ; reset
  288. REVERSE_ROW:    CALL    SET_CURSOR
  289.         CALL    REVERSE         ; reverse video at cursor
  290.         DEC     DL              ; column number
  291.         CMP     DL,BL           ; beyond beginning?
  292.         JL      BR_FINISH       ; finish reversing
  293.         JMP     REVERSE_ROW     ; next column
  294. BOT_LEFT:       CMP     DL,BL           ; compare to left
  295.         JE      BOT_BADKE       ; can't move left
  296.         DEC     DL              ; new bottom right location
  297.         PUSH    DX              ; save
  298.         INC     DL              ; reset
  299. REVERSE_COL:    CALL    SET_CURSOR
  300.         CALL    REVERSE         ; reverse video at cursor
  301.         DEC     DH              ; row number
  302.         CMP     DH,BH           ; at end?
  303.         JGE     REVERSE_COL     ; next row
  304. BR_FINISH:      CALL    BURY_CURSOR
  305.         POP     DX              ; recover current location
  306.         JMP     BOT_NEXTKE      ; get next move
  307. BOT_RIGHT:      CMP     DL,LAST_COL     ; can't move beyond last column
  308.         JE      BOT_BADKE
  309.         INC     DL              ; new bottom right location
  310.         PUSH    DX              ; save
  311.         JMP     REVERSE_COL     ; add column
  312. BOT_DOWN:       MOV     AX,DX
  313.         SUB     AH,BH           ; number rows
  314.         CMP     AH,5            ; max rows (is 6)
  315.         JE      BOT_BADKE
  316.         CMP     DH,LAST_LINE    ; can't move beyond last row
  317.         JE      BOT_BADKE
  318.         INC     DH              ; new bottom right location
  319.         PUSH    DX              ; save
  320.         JMP     REVERSE_ROW     ; add row
  321. ;-----------------------------------------------------------------------
  322. ; Display Print Menu
  323. ;-----------------------------------------------------------------------
  324. PRINT_MENU:     CALL    PRINT_WINDOW    ; display print window
  325. SET_SIZE:       CALL    SET_HILITE      ; set size and return hilites
  326. PR_NEXT:        CALL    GET_CHAR
  327.         CMP     AL,CR           ; print if carriage return
  328.         JE      PRINT_ENV       ; print envelope
  329.         CMP     AL,ESCAPE       ; exit without printing
  330.         JNE     PR_NOTESC
  331.         CALL    PRINT_WINDOW    ; remove print window
  332.         JMP     SCREEN_RST      ; restore screen and exit
  333. PR_NOTESC:      OR      AL,AL           ; test for extended code
  334.         JZ      PR_CODE
  335. PR_BADKE:       CALL    BEEP
  336.         JMP     PR_NEXT         ; get another character
  337. PR_CODE:        SUB     AH,59           ; convert function keys to digit codes
  338.         JL      PR_BADKE
  339.         JG      PR_CODE_2
  340.         AND     STATUS,NOT ENV_SIZE_BIT    ; Small Envelope
  341.         JMP     SET_SIZE
  342. PR_CODE_2:      SUB     AH,2
  343.         JG      PR_BADKE        ; F4 or greater
  344.         JE      PR_CODE_3       ; F3
  345.         OR      STATUS,ENV_SIZE_BIT    ; Large Envelope
  346.         JMP     SET_SIZE
  347. PR_CODE_3:      XOR     STATUS,PR_RET_ADD    ; toggle return address bit
  348.         JMP     SET_SIZE
  349. ;-----------------------------------------------------------------------
  350. ; print envelope here
  351. ;-----------------------------------------------------------------------
  352. PRINT_ENV:      CALL    PRINT_WINDOW    ; remove print display window
  353.         MOV     SI,OFFSET RESET_LJ    ; reset printer
  354.         CALL    OUT_STRING
  355.         JNC     PRINT_OK
  356. ;-----------------------------------------------------------------------
  357. ; printer error  -- beep twice and try again
  358. ;-----------------------------------------------------------------------
  359.         CALL    BEEP
  360.         XOR     CX,CX
  361. DUMB_LOOP:      LOOP    DUMB_LOOP       ; slight delay
  362.         CALL    BEEP
  363.         JMP     PRINT_MENU      ; try again
  364. PRINT_OK:       MOV     SI,OFFSET FONT  ; set fonts, etc.
  365.         CALL    OUT_STRING
  366. ;-----------------------------------------------------------------------
  367. ; set margins for location of return address
  368. ;-----------------------------------------------------------------------
  369.         TEST    STATUS,LJ_MODEL        ; this affects top margin
  370.         MOV     AX,TMARG_RET_2       ; LJ Series 2
  371.         JNZ     SET_TOP_RET
  372.         TEST    STATUS,ENV_SIZE_BIT      ; affects top on LJ & LJ+
  373.         MOV     AX,TMARG_RET_S       ; Small on original
  374.         JZ      SET_TOP_RET
  375.         MOV     AX,TMARG_RET_L       ; Large on original
  376. SET_TOP_RET:    MOV     WORD PTR MODELX,AX      ; set top margin
  377.         TEST    STATUS,ENV_SIZE_BIT      ; this affects left margin
  378.         MOV     AX,LMARG_RET_S       ; small envelope
  379.         JZ      SET_LEFT_RET
  380.         MOV     AX,LMARG_RET_L       ; large envelope
  381. SET_LEFT_RET:   MOV     WORD PTR ENV_SIZE,AX      ; set left margin
  382.         CALL    SET_MARGINS         ; send commands to printer
  383. ;-----------------------------------------------------------------------
  384. ; print the return address if requested
  385. ;-----------------------------------------------------------------------
  386.         MOV     CX,9                ; lines to skip if no return
  387.         TEST    STATUS,PR_RET_ADD      ; print return address?
  388.         JZ      TO_ADDRESS           ; no return address
  389.         MOV     SI,OFFSET RET_ADD      ; print return address
  390.         CALL    OUT_STRING
  391.         MOV     CX,6                ; lines to skip if return addr
  392. ;-----------------------------------------------------------------------
  393. ; print 'to' address  -- first set margins
  394. ;-----------------------------------------------------------------------
  395. TO_ADDRESS:     CALL    LINE_FEED           ; skip a line
  396.         LOOP    TO_ADDRESS          ; count in CX
  397.         TEST    STATUS,ENV_SIZE_BIT      ; this affects left margin
  398.         MOV     AX,LMARG_ADD_S      ; small envelope
  399.         JZ      SET_LEFT_ADD
  400.         MOV     AX,LMARG_ADD_L       ; large envelope
  401. SET_LEFT_ADD:   MOV     WORD PTR ENV_SIZE,AX      ; set left margin
  402.         CALL    SET_LEFT_ONLY       ; send commands to printer
  403. ;-----------------------------------------------------------------------
  404. ; read address from reverse-video part of screen - send to printer
  405. ;-----------------------------------------------------------------------
  406.         XOR     CX,CX
  407.         MOV     AX,BOTRIGHT
  408.         MOV     DX,UPLEFT       ; starting loc on screen
  409.         SUB     AX,DX           ; rows-1 and cols-1 in AX
  410.         MOV     CL,AH           ; rows - 1
  411.         INC     AL              ; columns
  412.         MOV     ADDR_COLS,AL    ; save columns in address
  413.         JCXZ    LAST_ROW        ; only one line
  414. NEXT_ROW:       PUSH    CX              ; save loop counter
  415.         PUSH    DX              ; save cursor location
  416.         CALL    OUT_LINE        ; print line from screen
  417.         CALL    LINE_FEED       ; send carriage return
  418.         POP     DX              ; retrieve cursor
  419.         INC     DH              ; next row
  420.         POP     CX              ; retrieve counter
  421.         LOOP    NEXT_ROW
  422. LAST_ROW:       CALL    OUT_LINE            ; print last line
  423.         MOV     SI,OFFSET RESET_LJ      ; reset printer
  424.         CALL    OUT_STRING      ; also flushes printer buffer
  425. ;-----------------------------------------------------------------------
  426. ; restore screen to normal video
  427. ;-----------------------------------------------------------------------
  428. SCREEN_RST:     MOV     DX,UPLEFT
  429.         MOV     AX,BOTRIGHT
  430.         SUB     AX,DX
  431.         ADD     AX,0101H        ; rows and columns in AX
  432.         XOR     CX,CX
  433.         MOV     CL,AH           ; number rows
  434.         XOR     AH,AH
  435.         MOV     SI,AX           ; save columns
  436. ROW_RESTORE:    PUSH    CX
  437.         MOV     CX,SI           ; number columns
  438.         PUSH    DX              ; save cursor location
  439. COL_RESTORE:    CALL    SET_CURSOR
  440.         CALL    REVERSE         ; reset video
  441.         INC     DL              ; next column
  442.         LOOP    COL_RESTORE
  443.         POP     DX
  444.         INC     DH              ; next row
  445.         POP     CX
  446.         LOOP    ROW_RESTORE
  447. ;-----------------------------------------------------------------------
  448. ; reset text in window for upper left corner message
  449. ;-----------------------------------------------------------------------
  450. ENV_EXIT:       MOV     SI,OFFSET TEXT_UPPER  ; top message
  451.         MOV     DI,OFFSET MENU_BLOCK+28  ; window location
  452.         CALL    MOV_TEXT
  453.         MOV     DI,OFFSET MENU_BLOCK+50  ; window location
  454.         CALL    MOV_TEXT        ; mov 'left ' message
  455.         RET
  456.  
  457. ENVL_MAIN       ENDP
  458. ;======================================================================
  459. ; output a string to the printer
  460. ; string address in SI, terminated by ASCII0
  461. ;-----------------------------------------------------------------------
  462. OUT_STRING      PROC    NEAR
  463.  
  464.         LODSB                   ; next character
  465.         OR      AL,AL           ; check for 0
  466.         JZ      OUT_STR_X       ; CY is clear
  467.         CALL    OUT_CHAR        ; output character
  468.         JC      OUT_STR_X       ; error return
  469.         JMP     OUT_STRING      ; get next character
  470. OUT_STR_X:      RET                     ; ret on ASCII0
  471.  
  472. OUT_STRING      ENDP
  473. ;======================================================================
  474. ; print line of text from screen at cursor location DX
  475. ;      number to print in ADDR_COLS
  476. ;-----------------------------------------------------------------------
  477. OUT_LINE        PROC    NEAR
  478.  
  479.         PUSH    CX              ; save counter
  480.         XOR     CX,CX
  481.         MOV     CL,ADDR_COLS    ; column counter
  482. LOOP_LINE:      CALL    SET_CURSOR      ; cursor to location DX
  483.         MOV     AH,8            ; read character
  484.         CALL    VIDEO_INT       ; into AL
  485.         PUSH    DX              ; save location
  486.         CALL    OUT_CHAR        ; print character
  487.         POP     DX              ; recover location
  488.         INC     DL              ; next column
  489.         LOOP    LOOP_LINE
  490.         CALL    BURY_CURSOR
  491.         POP     CX              ; recover counter
  492.         RET
  493. OUT_LINE        ENDP
  494. ;======================================================================
  495. ; skip line by sending  CR LF combination   alters  AX  DX  SI
  496. ;-----------------------------------------------------------------------
  497. LINE_FEED       PROC    NEAR
  498.  
  499.         MOV     SI,OFFSET SKIP_LINE
  500.         CALL    OUT_STRING      ; send characters  CR  LF  0
  501.         RET
  502.  
  503. LINE_FEED       ENDP
  504. ;======================================================================
  505. ; output character in AL to printer    alters  AX  DX
  506. ;-----------------------------------------------------------------------
  507. OUT_CHAR        PROC    NEAR
  508.  
  509.         MOV     DX,PRINT_PORT   ; printer port number
  510.         CMP     DX,2            ; 0 to 2 are LPT1-LPT3
  511.         JG      SERIAL
  512.         XOR     AH,AH           ; print character
  513.         INT     17H             ; BIOS printer
  514.         TEST    AH,101001B      ; check for printer error
  515. TEST_ERROR:     JZ      NO_ERROR        ; normal return
  516. RET_ERROR:      STC                     ; error return
  517.         RET
  518. SERIAL:         SUB     DX,3            ; COM port number
  519.         MOV     AH,1            ; send char - DX already set
  520.         INT     14H             ; BIOS
  521.         TEST    AH,10000000B    ; check for printer error
  522.         JMP     TEST_ERROR      ; test for error
  523.  
  524. OUT_CHAR        ENDP
  525. ;======================================================================
  526. ; Set top and left margins for return or to address
  527. ;-----------------------------------------------------------------------
  528. SET_MARGINS     PROC    NEAR
  529.  
  530.         MOV     SI,OFFSET TOP_MARGIN  ; top margin
  531.         CALL    OUT_STRING
  532. SET_LEFT_ONLY   LABEL   NEAR
  533.         MOV     SI,OFFSET LEFT_MARGIN ; left margin
  534.         CALL    OUT_STRING
  535.         RET
  536.  
  537. SET_MARGINS     ENDP
  538. ;======================================================================
  539. ; Calculate offset for NEAR  JMP to  LABEL
  540. ; extended code in AH (from GETCHAR)   BX points to end of JumpTable
  541. ; Returns JUMP offset in DI     No match if CY flag set
  542. ;-----------------------------------------------------------------------
  543. GET_JMP_OFF     PROC    NEAR
  544.  
  545.         MOV     DI,OFFSET KEYTAB  ; table of key codes
  546.         MOV     CX,4            ; number of codes
  547.         XCHG    AH,AL           ; code into AL
  548.         REPNZ   SCASB           ; look for match
  549.         JNZ     RET_ERROR       ; no match
  550.         MOV     DI,BX           ; last entry in table
  551.         SHL     CX,1            ; 2 bytes/word
  552.         SUB     DI,CX           ; offset
  553. NO_ERROR:       CLC                     ; normal return
  554.         RET
  555.  
  556. GET_JMP_OFF     ENDP
  557. ;======================================================================
  558. ; set highlites in printer menu
  559. ;-----------------------------------------------------------------------
  560. SET_HILITE      PROC    NEAR
  561.  
  562.         MOV     CX,3            ; 3 lines to reset
  563.         MOV     DX,HILITE_LOC   ; beginning location of Small
  564.         PUSH    DX              ; save
  565.         PUSH    DX              ; save again
  566. SET_H_LOOP:     PUSH    DX              ; save
  567.         MOV     BL,07H          ; normal video
  568.         CALL    SET_ATTRIB      ; set attribute byte
  569.         POP     DX              ; Small message
  570.         INC     DH              ; next row
  571.         LOOP    SET_H_LOOP
  572.         POP     DX              ; retrieve HILITE_LOC
  573.         TEST    STATUS,ENV_SIZE_BIT  ; test for small
  574.         JZ      SET_HIL_2       ; not set = small
  575.         INC     DH              ; Large to be hilited
  576. SET_HIL_2:      MOV     BL,70H          ; reverse video
  577.         CALL    SET_ATTRIB
  578.         POP     DX              ; retrieve HILITE_LOC
  579.         ADD     DH,2            ; location of 'RtAdd'
  580.         TEST    STATUS,PR_RET_ADD  ; test for print of rt-add
  581.         JZ      SET_HIL_X       ; no print if 0
  582.         CALL    SET_ATTRIB      ; color should still be in BL
  583. SET_HIL_X:      CALL    BURY_CURSOR     ; bury cursor
  584.         RET
  585.  
  586. SET_HILITE      ENDP
  587. ;======================================================================
  588. ; set attributes --  start at DX (cursor)
  589. ; change 5 attributes to  BL
  590. ;-----------------------------------------------------------------------
  591. SET_ATTRIB      PROC    NEAR
  592.  
  593.         PUSH    CX
  594.         MOV     CX,5            ; attributes to set
  595. SET_ATT_LOOP:   CALL    SET_CURSOR
  596.         MOV     AH,8            ; read character
  597.         CALL    VIDEO_INT
  598.         PUSH    CX
  599.         MOV     AH,9            ; write character
  600.         MOV     CX,1            ; one character
  601.         CALL    VIDEO_INT       ; attribute in BL
  602.         INC     DL              ; next position
  603.         POP     CX
  604.         LOOP    SET_ATT_LOOP    ; next character
  605.         POP     CX
  606.         RET
  607.  
  608. SET_ATTRIB      ENDP
  609. ;======================================================================
  610. BEEP            PROC    NEAR
  611.         PUSH    AX
  612.         MOV     AX,0E07H        ; Beep (ASCII 7)
  613.         INT     10H             ; BIOS
  614.         POP     AX
  615.         RET
  616. BEEP            ENDP
  617. ;======================================================================
  618. ; call BIOS video INT   function in AH
  619. ;-----------------------------------------------------------------------
  620. VIDEO_INT       PROC    NEAR
  621.  
  622.         PUSH    BX
  623.         MOV     BH,VID_PAGE     ; page number
  624.         INT     10H             ; BIOS video
  625.         POP     BX
  626.         RET
  627.  
  628. VIDEO_INT       ENDP
  629. ;======================================================================
  630. ; bury cursor    alters   DX
  631. ;-----------------------------------------------------------------------
  632. BURY_CURSOR     PROC    NEAR
  633.  
  634.         MOV    DH,[LAST_LINE]
  635.         INC    DH
  636.         XOR    DL,DL
  637. ;-----------------------------------------------------------------------
  638. ; set cursor to position in  DH  DL
  639. ;-----------------------------------------------------------------------
  640. SET_CURSOR      LABEL   NEAR
  641.  
  642.         PUSH    AX
  643.         MOV     AH,2            ; set cursor
  644. VIDEO_CURSOR:   CALL    VIDEO_INT       ; BIOS video
  645.         POP     AX
  646.         RET
  647. ;-----------------------------------------------------------------------
  648. ; get cursor in DX ( DH  DL )
  649. ;-----------------------------------------------------------------------
  650. GET_CURSOR      LABEL   NEAR
  651.  
  652.         PUSH    AX
  653.         MOV     AH,3            ; get cursor
  654.         JMP     VIDEO_CURSOR    ; BIOS video
  655.  
  656. BURY_CURSOR     ENDP
  657. ;======================================================================
  658. ; get character from keyboard
  659. ;-----------------------------------------------------------------------
  660. GET_CHAR        PROC    NEAR
  661.  
  662.         XOR    AH,AH
  663.         INT    16H
  664.         RET
  665.  
  666. GET_CHAR        ENDP
  667. ;======================================================================
  668. ; reverse video attribute at cursor location    alters  AX
  669. ;-----------------------------------------------------------------------
  670. REVERSE         PROC    NEAR
  671.  
  672.         PUSH    BX
  673.         PUSH    CX
  674.         MOV     AH,8            ; read character
  675.         CALL    VIDEO_INT       ; attribute to AH
  676.         MOV     CL,4
  677.         ROR     AH,CL           ; reverse video attribute
  678.         MOV     BL,AH           ; need attribute in BL
  679.         MOV     AH,9            ; write character
  680.         MOV     CX,1            ; write 1 character
  681.         CALL    VIDEO_INT       ; attribute in BL
  682.         POP     CX
  683.         POP     BX
  684.         RET
  685. REVERSE         ENDP
  686. ;======================================================================
  687. ;  Display Window with Instructions for Blocking out address
  688. ;  SI offset in memory       DX screen location
  689. ;  CX chars/row              AX number rows
  690. ;-----------------------------------------------------------------------
  691. BLOCK_WINDOW    PROC    NEAR
  692.  
  693.         MOV     DH,2            ; row start
  694.         MOV     DL,[NUM_COLS]   ; number columns in mode
  695.         SUB     DL,12           ; number columns
  696.         CMP     BYTE PTR [UPLEFT],27  ; check start column
  697.         JLE     BLOCK_WIND_2
  698.         XOR     DL,DL           ; start in first column
  699. BLOCK_WIND_2:
  700.         MOV     SI,OFFSET MENU_BLOCK  ; memory LOCATION
  701.         MOV     AX,4            ; rows
  702.         MOV     CX,12           ; columns
  703. ;-----------------------------------------------------------------------
  704. ;  swap window with screen - use BIOS
  705. ;   call with screen loc in DX        memory image at SI
  706. ;             rows in AX              columns in CX
  707. ;    alters  AX  BX  CX  DX  SI
  708. ;-----------------------------------------------------------------------
  709. WINDOW          LABEL   NEAR
  710.  
  711.         MOV     [START_COL],DL  ; starting column for swap
  712. LOOP_ROW:       PUSH    AX              ; rows
  713.         PUSH    CX              ; columns
  714. LOOP_COL:       CALL    SET_CURSOR
  715.         MOV     AH,8            ; read character and attrib
  716.         CALL    VIDEO_INT
  717.         XCHG    AX,DS:[SI]      ; swap with memory
  718.         INC     SI
  719.         INC     SI              ; next image location
  720.         MOV     BL,AH           ; attribute
  721.         MOV     AH,9            ; write character and attrib
  722.         PUSH    CX
  723.         MOV     CX,1            ; write only one character
  724.         CALL    VIDEO_INT
  725.         POP     CX
  726.         INC     DL              ; move cursor
  727.         LOOP    LOOP_COL        ; next character and attribute
  728.         POP     CX              ; number columns
  729.         INC     DH              ; next row
  730.         MOV     DL,[START_COL]  ; starting column
  731.         POP     AX              ; rows to move
  732.         DEC     AX              ; row moved
  733.         JNZ     LOOP_ROW        ; next row
  734.         CALL    BURY_CURSOR
  735.         RET
  736.  
  737. BLOCK_WINDOW    ENDP
  738. ;======================================================================
  739. ;  Display Print Command Window
  740. ;  SI offset in memory       DX screen location
  741. ;  CX chars/row              AX number rows
  742. ;-----------------------------------------------------------------------
  743. PRINT_WINDOW    PROC    NEAR
  744.  
  745.         MOV     AH,2            ; row start
  746.         MOV     AL,[NUM_COLS]   ; number columns in mode
  747.         SUB     AL,10           ; start column
  748.         MOV     DX,AX           ; save
  749.         ADD     AX,0104H        ; location for highlight
  750.         MOV     [HILITE_LOC],AX ; save
  751.         MOV     SI,OFFSET MENU_PRINT  ; memory location
  752.         MOV     AX,8            ; rows
  753.         MOV     CX,10           ; columns
  754.         JMP     WINDOW          ; swap
  755.  
  756. PRINT_WINDOW    ENDP
  757. ;======================================================================
  758. ; move text in memory    from  DS:[SI]   to  ES:[DI]
  759. ;   the destination is assumed to be a screen image w/attribute bytes
  760. ;  ASCII 0 terminates move             alters  AL
  761. ;  sets  SI  and  DI  to next space in sequences
  762. ;-----------------------------------------------------------------------
  763. MOV_TEXT        PROC    NEAR
  764.  
  765.         LODSB                   ; next character
  766.         OR      AL,AL
  767.         JNZ      MOV_TEXT_X      ; ASCII 0
  768.         RET
  769. MOV_TEXT_X:     STOSB                   ; send to display
  770.         INC     DI              ; 2 bytes/video
  771.         JMP     MOV_TEXT        ; get next character
  772.  
  773. MOV_TEXT        ENDP
  774. ;======================================================================
  775. ; this part of code will not remain resident
  776. ;-----------------------------------------------------------------------
  777. INSTRUCT$       DB      "/U - Uninstall",CR,LF
  778.         DB      "/Pxx - Printer Port, xx=L1-L3,C1-C4. Default"
  779.         DB    "=L1 (LPT1)",CR,LF
  780.         DB      "/Ln - LaserJet Model"
  781.         DB    " n=1 original & +, n=2 Series 2. Default=2",CR,LF
  782.         DB      "/R - Change Return Address",LF,"$"
  783.  
  784. WHITE           DB      " ,;",9         ; space, comma, semicolon, tab
  785. FILENAME        DB      "ENVELOPE.COM",0
  786. RESIDENT_SEG    DW      0               ; segment of installed ENVELOPE
  787.  
  788. INSTALLED$      DB      CR,LF,"Port "
  789. PORT$           DB      "LPT1, Model LJ"
  790. MODEL$          DB      "2, Hotkey is Alt-E$"
  791. ALREADY_IN$     DB      "Resident$"
  792. NOT_INST$       DB      "NOT Resident$"
  793. UNINSTALL$      DB      "Uninstalled$"
  794. NO_UN_INST$     DB      "Can't Uninstall$"
  795.  
  796. SAVE_TO_FILE$   DB      "Save new ENVELOPE.COM?$"
  797. FILE_ERROR$     DB      "FILE ERROR - nothing saved$"
  798. FILE_UPDATE$    DB      "ENVELOPE.COM updated$"
  799. RET_UPDATE$     DB      "Resident Return Address Updated$"
  800.  
  801. PORT_NAMES      DB      "LPT1",0,"LPT2",0,"LPT3",0
  802.         DB    "COM1",0,"COM2",0,"COM3",0,"COM4",0
  803. ;----------------------------------------------------------------------
  804. INSTALL        PROC    NEAR
  805.     ASSUME  CS:CSEG,DS:CSEG,ES:CSEG,SS:CSEG
  806.  
  807.         CLD                     ; standard UP direction
  808.         MOV     DX,OFFSET COPYRIGHT$
  809.         MOV     AH,9            ; copyright message
  810.         INT     21H             ; DOS
  811.         MOV     DX,OFFSET INSTRUCT$
  812.         CALL    MESSAGE
  813.  
  814.         MOV    NUM_COLS,80
  815.         MOV    LAST_COL,79
  816.         MOV    LAST_LINE,24
  817.         MOV    PRINT_PORT,0
  818.         MOV    STATUS,5
  819. ;-----------------------------------------------------------------------
  820. ; first check if ENVELOPE already installed and set flag in STATUS
  821. ;-----------------------------------------------------------------------
  822.     ASSUME    ES:NOTHING
  823.         NOT     WORD PTR [START]  ; Modify
  824.         MOV     BX,600H         ; segment to compare
  825.         MOV     AX,CS           ; this segment
  826. FIND_RES:       INC     BX              ; next paragraph
  827.         MOV     ES,BX           ; ES is search segment
  828.         CMP     AX,BX           ; current segment?
  829.         JE      CHECK_TAIL      ; not in memory  flag is 0
  830.         MOV     SI,OFFSET START ; compare static part of data
  831.         MOV     DI,SI           ; same offset in both strings
  832.         MOV     CX,16           ; bytes to compare
  833.         REP     CMPSB           ; compare  DS:SI  to  ES:DI
  834.         OR      CX,CX           ; all matched
  835.         JNZ     FIND_RES        ; check next paragraph
  836.         OR      STATUS,INSTALLED  ; set bit for installed
  837.         MOV     RESIDENT_SEG,BX   ; save installed segment
  838.         MOV     DX,OFFSET ALREADY_IN$
  839.         CALL    MESSAGE
  840. ;-----------------------------------------------------------------------
  841. ; Now check command tail for switches
  842. ; DS  points to CODE   and to  PSP
  843. ;-----------------------------------------------------------------------
  844. CHECK_TAIL:
  845.         PUSH    DS              ; reset extra segment
  846.         POP     ES
  847.     ASSUME    ES:CSEG
  848.         MOV     SI,80H          ; location of command tail
  849.         LODSB                   ; length in AL
  850.         OR      AL,AL           ; Check if parameters
  851.         JNZ     CHECK_0         ; commands to check
  852. ATTEMPT_INST:   TEST    STATUS,INSTALLED
  853.         JNZ     RLH_1
  854.         JMP     OK_INSTALL      ; proceed with default install
  855. RLH_1:        MOV    AX,4C01H    ;Terminate with return code
  856.         INT    21H
  857. ;-----------------------------------------------------------------------
  858. ; Decode command line using brute force
  859. ;-----------------------------------------------------------------------
  860. CHECK_0:        MOV     BL,AL           ; character count
  861. CHECK_1:        OR      BL,BL           ; more commands?
  862.         JZ      ATTEMPT_INST    ; processing complete
  863.         LODSB                   ; next character
  864.         DEC     BL              ; keep count current
  865.         MOV     DI,OFFSET WHITE  ; delimiters and space
  866.         MOV     CX,4            ; number to check
  867.         REPNE   SCASB
  868.         JE      CHECK_1         ; look for next character
  869. CHECK_2:        CMP     AL,"/"          ; normal delimiter
  870.         JNE     ATTEMPT_INST    ; anything else - default
  871. ;-----------------------------------------------------------------------
  872. ; check character after slash
  873. ;-----------------------------------------------------------------------
  874.         OR      BL,BL           ; if / terminates
  875.         JZ      ATTEMPT_INST    ; then try default install
  876.         LODSB                   ; character after slash
  877.         AND     AL,01011111B    ; capitalize
  878.         CMP     AL,"U"          ; uninstall
  879.         JNE     CHECK_3
  880.         JMP     UNINSTALL       ; attempt to uninstall
  881. CHECK_3:        CMP     AL,"P"          ; check for port input
  882.         JNE     CHECK_4
  883.         CALL    GET_PORT
  884.         JC      ATTEMPT_INST    ; if input errors
  885.         JMP     CHECK_1         ; continue with input
  886. CHECK_4:        CMP     AL,"L"          ; check LJ Model input
  887.         JNE     CHECK_5
  888.         CALL    GET_MODEL
  889.         JC      ATTEMPT_INST    ; if input errors
  890.         JMP     CHECK_1         ; continue with input
  891. CHECK_5:        CMP     AL,"R"          ; input new return address
  892.         JNE     ATTEMPT_INST    ; no match
  893.         CALL    GET_RET_ADD
  894. ;-----------------------------------------------------------------------
  895. ; Prompt for saving new Return Address to ENVELOPE.COM
  896. ;-----------------------------------------------------------------------
  897. CHECK_SAVE:     MOV     DX,OFFSET SAVE_TO_FILE$
  898.         MOV    AH,9
  899.         INT    21H
  900. ;;;        CALL    MESSAGE
  901. ;;;        CALL    GET_CHAR        ; get response
  902.  
  903.         MOV    AH,1        ;DOS get char fn
  904.         INT    21H        ; allows for redirection
  905.  
  906.         AND     AL,01011111B    ; capitalize
  907.         CMP     AL,"Y"
  908.         JNE     NO_RET_SAVE
  909. ;-----------------------------------------------------------------------
  910. ; save to file here  - attempt to open file
  911. ;-----------------------------------------------------------------------
  912.         NOT    WORD PTR [START]
  913.         MOV     AH,3CH            ;Create file
  914.         MOV     DX,OFFSET FILENAME    ; name of ENVELOPE.COM
  915.         XOR    CX,CX            ;Normal attribute
  916.         INT     21H            ; DOS
  917.         JNC     SAV_FILE_OK
  918. SAV_FILE_ERR:   MOV     DX,OFFSET FILE_ERROR$
  919.         JMP     SHORT  SAV_FILE_MSG  ; display string, proceed
  920. SAV_FILE_OK:    MOV     BX,AX           ; file handle
  921.         MOV     AH,40H          ; write to file
  922.         MOV     CX,(OFFSET COM_SIZE - OFFSET CSEG - 100H) ;bytes
  923.         MOV    DX,100H
  924.         INT     21H             ; DOS
  925.         JC      SAV_FILE_ERR
  926.         MOV     AH,3EH          ; close file handle
  927.         INT     21H             ; DOS
  928.         MOV     DX,OFFSET FILE_UPDATE$
  929. SAV_FILE_MSG:    CALL    MESSAGE
  930.         NOT    WORD PTR [START]
  931. NO_RET_SAVE:
  932.         TEST    STATUS,INSTALLED  ; is ENVELOPE installed?
  933.         JZ      OK_INSTALL      ; install
  934.         MOV     SI,OFFSET RET_ADD
  935.         MOV     DI,SI           ; same offset
  936.         MOV     AX,RESIDENT_SEG ; segment of installed ENVELOPE
  937.         MOV     ES,AX           ; destination
  938.         MOV     CX,LENGTH_RET   ; bytes to move
  939.         REP     MOVSB
  940.         MOV     DX,OFFSET RET_UPDATE$
  941.         CALL    MESSAGE
  942.         MOV    AX,4C05H
  943.         INT    21H
  944. ;-----------------------------------------------------------------------
  945. ; final preparations for installation of ENVELOPE
  946. ; set printer model and port name in PRINT_MENU
  947. ;-----------------------------------------------------------------------
  948. OK_INSTALL:     PUSH    CS
  949.         POP     ES              ; reset segment
  950.     ASSUME    ES:CSEG
  951.         MOV     DI,OFFSET MENU_PRINT+116  ; location for model
  952.         MOV     AL," "          ; original LJ or LJ+
  953.         TEST    STATUS,LJ_MODEL ; check for LJ Series 2
  954.         JZ      SET_MODEL
  955.         MOV     AL,"2"          ; LJ Series II
  956. SET_MODEL:      STOSB
  957.         MOV     MODEL$,AL       ; Model in message
  958.         MOV     DI,OFFSET MENU_PRINT+102  ; location for port
  959.         MOV     SI,OFFSET PORT_NAMES      ; location for names
  960.         MOV     AX,PRINT_PORT   ; 0 through 6    LPT1 - COM4
  961.         ADD    SI,AX
  962.         SHL    AX,1
  963.         SHL    AX,1
  964.         ADD     SI,AX           ; offset in memory in SI
  965.         PUSH    SI              ; save location
  966.         CALL    MOV_TEXT        ; move text to video image
  967.         POP     SI              ; location of port name
  968.         MOV     DI,OFFSET PORT$ ; location in message
  969.         MOVSW
  970.         MOVSW                   ; move 4 bytes
  971. ;-----------------------------------------------------------------------
  972. ; check for EGA (or VGA) and set byte if present
  973. ;-----------------------------------------------------------------------
  974.         MOV     AH,12H          ; special EGA function
  975.         MOV     BL,10H          ; return EGA information
  976.         INT     10H             ; BIOS video
  977.         CMP     BL,10H          ; if BL unchanged then
  978.         JE      ENV_REL         ; no  EGA or VGA
  979.         OR      STATUS,EGA      ; set EGA bit
  980. ;-----------------------------------------------------------------------
  981. ; Release environment block
  982. ;-----------------------------------------------------------------------
  983. ENV_REL:        MOV     BX,WORD PTR DS:[2CH]   ; environment block
  984.         MOV     ES,BX           ; segment
  985.     ASSUME    ES:NOTHING
  986.         MOV     AH,49H          ; free memory block
  987.         INT     21H             ; DOS
  988. ;-----------------------------------------------------------------------
  989. ;  go resident
  990. ;-----------------------------------------------------------------------
  991.         MOV     AX,3509H            ; get interrupt vector 09h
  992.         INT     21H                 ; DOS
  993.  
  994.         MOV     WORD PTR OLD09H,BX        ; offset old interrupt 09h
  995.         MOV     WORD PTR OLD09H[2],ES     ; segment for above
  996.  
  997.         MOV     DX,OFFSET INT09H      ; new INT handler
  998.         MOV     AX,2509H              ; set interrupt vector 09h
  999.         INT     21H                   ; DOS
  1000.  
  1001.         MOV     DX,OFFSET INSTALLED$      ; installation message
  1002.         CALL    MESSAGE
  1003.  
  1004.         MOV     DX,OFFSET INSTALL      ; save code up to INSTALL
  1005.         INT     27H                    ; The infamous TSR interrupt
  1006. ;-----------------------------------------------------------------------
  1007. ; attempt to uninstall ENVELOPE
  1008. ;-----------------------------------------------------------------------
  1009. UNINSTALL:      TEST    STATUS,INSTALLED  ; first see if it is resident
  1010.         JNZ     UNINST_2          ; it is in memory
  1011.         MOV     DX,OFFSET NOT_INST$
  1012.         CALL    MESSAGE
  1013.         MOV    AX,4C02H
  1014.         INT    21H
  1015. UNINST_2:       MOV     AX,3509H        ; get segment of keyboard INT
  1016.         INT     21H             ; DOS
  1017.     ASSUME    ES:NOTHING
  1018.         MOV     AX,ES           ; current segment
  1019.         CMP     AX,RESIDENT_SEG ; segment of ENVELOPE
  1020.         JE      UNINST_3        ; OK to uninstall
  1021. NO_UNINST:      MOV     DX,OFFSET NO_UN_INST$
  1022.         MOV    AX,4C03H
  1023.         INT    21H
  1024. ;-----------------------------------------------------------------------
  1025. ; OK to uninstall
  1026. ;-----------------------------------------------------------------------
  1027. UNINST_3:       MOV     ES,RESIDENT_SEG     ; segment of installed ENVELOPE
  1028.         NOT     WORD PTR ES:[START] ; don't confuse next install
  1029.         LDS     DX,ES:[OLD09H]      ; old INT09H interrupt vector
  1030.     ASSUME    DS:NOTHING
  1031.         MOV     AX,2509H        ; reset vector 09H
  1032.         INT     21H             ; DOS
  1033.         PUSH    CS              ; reset DS to code
  1034.         POP     DS
  1035.     ASSUME  DS:CSEG
  1036.         MOV     AH,49H          ; free memory block in ES
  1037.         INT     21H             ; DOS
  1038.         JC      NO_UNINST       ; error return
  1039.         MOV     DX,OFFSET UNINSTALL$
  1040.         CALL    MESSAGE
  1041.         MOV    AX,4C04H
  1042.         INT    21H
  1043.  
  1044. INSTALL        ENDP
  1045. ;-----------------------------------------------------------------------
  1046. ; Read port number from command tail  SI points to next character
  1047. ;  BL characters left      CY set on return if error
  1048. ;-----------------------------------------------------------------------
  1049. GET_PORT        PROC    NEAR
  1050.  
  1051.         CALL    GET_NEXT_CH     ; next character from tail
  1052.         JZ      G_ERROR_RET     ; no characters left
  1053.         AND     AL,01011111B    ; capitalize
  1054.         CMP     AL,"L"          ; parallel port
  1055.         JNE     GET_PORT_1
  1056.         CALL    GET_NEXT_CH     ; next character from tail
  1057.         SUB     AL,"1"          ; should be number
  1058.         CMP     AL,2            ; LPT3
  1059.         JBE     SET_PORT_NUM
  1060. G_ERROR_RET:    STC                     ; carry set on error
  1061.         RET
  1062. SET_PORT_NUM:   XOR     AH,AH           ; port number in AX
  1063.         MOV     PRINT_PORT,AX   ; save port number
  1064.         CLC                     ; carry clear on normal return
  1065.         RET
  1066. GET_PORT_1:     CMP     AL,"C"          ; serial port
  1067.         JNE     G_ERROR_RET
  1068.         CALL    GET_NEXT_CH     ; next character from tail
  1069.         SUB     AL,"1"          ; should be number
  1070.         CMP     AL,3            ; COM4
  1071.         JA      G_ERROR_RET
  1072.         ADD     AL,3            ;Skew port number in AX
  1073.         JMP     SET_PORT_NUM
  1074.  
  1075. GET_PORT        ENDP
  1076. ;-----------------------------------------------------------------------
  1077. ; Read LJ Model type from command tail  SI points to next character
  1078. ;  BL characters left      CY set on return if error
  1079. ;-----------------------------------------------------------------------
  1080. GET_MODEL       PROC    NEAR
  1081.  
  1082.         CALL    GET_NEXT_CH     ; next character from tail
  1083.         JZ      G_ERROR_RET     ; no characters left
  1084.         SUB     AL,"1"          ; should be number
  1085.         JB      G_ERROR_RET     ; illegal input
  1086.         JA      GET_MODEL_2
  1087.         AND     STATUS,NOT LJ_MODEL  ; clear model bit
  1088.         CLC
  1089.         RET
  1090. GET_MODEL_2:    CMP     AL,1
  1091.         JNE     G_ERROR_RET     ; illegal input
  1092.         OR      STATUS,LJ_MODEL  ; set model bit
  1093.         CLC
  1094.         RET
  1095.  
  1096. GET_MODEL       ENDP
  1097. ;-----------------------------------------------------------------------
  1098. ; enter new return address from keyboard
  1099. ;     if CY set on return  - then return address is not altered
  1100. ;  first display current return address
  1101. ;-----------------------------------------------------------------------
  1102. CURRENT_RET$    DB      "Current Address:$"
  1103. ACCEPT_RET$    DB    "Enter new address (Enter = no change).",CR,LF
  1104.         DB    "3 lines, 40 characters max.$"
  1105.  
  1106. GET_RET_ADD     PROC    NEAR
  1107.  
  1108.         MOV     DX,OFFSET CURRENT_RET$
  1109.         CALL    MESSAGE
  1110.         MOV     DX,OFFSET RET_ADD
  1111.         MOV     AH,9            ; display string
  1112.         INT     21H             ; DOS
  1113.         MOV     DX,OFFSET ACCEPT_RET$  ; accept prompt
  1114.         CALL    MESSAGE
  1115.         MOV     DX,OFFSET ADR_BUF    ;Single line buffer
  1116.         MOV    BYTE PTR [ADR_BUF],LINE_SIZE+1
  1117.         MOV     AH,0AH          ; buffered input
  1118.         INT     21H             ; DOS
  1119.         CMP     BYTE PTR ADR_BUF[1],0    ; any input?
  1120.         JE      GET_RET_ADD_2   ; first line read
  1121.         MOV     DI,OFFSET RET_ADD
  1122.         CALL    MOVE_LINE       ; blank line, move new, saves DI
  1123.         CALL    GET_LINE        ; get next line
  1124.         CALL    GET_LINE        ; get final line
  1125. GET_RET_ADD_2:  RET
  1126.  
  1127. GET_RET_ADD     ENDP
  1128. ;======================================================================
  1129. ; get line from STDIN and then move to return address
  1130. ;----------------------------------------------------------------------
  1131. GET_LINE        PROC    NEAR
  1132.  
  1133.         MOV     DX,OFFSET ADR_BUF
  1134.         MOV     AH,0AH          ; buffered input
  1135.         INT     21H             ; DOS
  1136.         ADD     DI,LINE_SIZE+2  ; next line
  1137. ;----------------------------------------------------------------------
  1138. ; blank line in return address
  1139. ;----------------------------------------------------------------------
  1140. MOVE_LINE       LABEL   NEAR
  1141.  
  1142.         PUSH    DI              ; save pointer
  1143.         PUSH    DI              ; save pointer
  1144.         MOV     CX,LINE_SIZE    ; # characters
  1145.         MOV     AL," "          ; set to blanks
  1146.         REP     STOSB
  1147.         POP     DI              ; recover address
  1148.         MOV     SI,OFFSET ADR_BUF+2   ; last input
  1149.         MOV     CL,BYTE PTR ADR_BUF[1] ; number characters  CH=0
  1150.         JCXZ    MOVE_LINE_X     ; no characters
  1151.         REP     MOVSB
  1152. MOVE_LINE_X:    MOV     DX,OFFSET CR_LF$  ; move to next line
  1153.         MOV     AH,9            ; display string
  1154.         INT     21H             ; DOS
  1155.         POP     DI
  1156.         RET
  1157.  
  1158. GET_LINE        ENDP
  1159. ;======================================================================
  1160. ; get next character from command tail (pointed to by SI)
  1161. ; BL set to number left     ZF set if not chacters left
  1162. ;----------------------------------------------------------------------
  1163. GET_NEXT_CH     PROC    NEAR
  1164.  
  1165.         LODSB                   ; next character
  1166.         DEC     BL              ; update count
  1167.         OR      BL,BL           ; check if last character
  1168.         RET
  1169.  
  1170. GET_NEXT_CH     ENDP
  1171. ;======================================================================
  1172. ; Write a line using the DOS print string function.
  1173. ;----------------------------------------------------------------------
  1174. CR_LF$          DB      CR,LF,"$"       ; carriage return  -- line feed
  1175.  
  1176. MESSAGE        PROC    NEAR
  1177.  
  1178.         MOV    AH,9
  1179.         INT    21H
  1180.         MOV    DX,OFFSET CR_LF$
  1181.         MOV    AH,9
  1182.         INT    21H
  1183.         RET
  1184.  
  1185. MESSAGE        ENDP
  1186. ;======================================================================
  1187. COM_SIZE    =    $
  1188. PC        =    $
  1189. ADR_BUF        =    PC        ;ADR_BUF DB 41, 0, 41 DUP(0)
  1190.  
  1191. CSEG            ENDS
  1192.         END     START
  1193.